package top.hours48.ddbearapi.advice;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import top.hours48.ddbearapi.model.RespVO;
import top.hours48.ddbearapi.model.exception.BusinessCode;
import top.hours48.ddbearapi.model.exception.BusinessException;

@RestControllerAdvice(basePackages = {"top.hours48.ddbearapi"})
public class ContorllerExceptionAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // response是ResultVo类型，或者注释了NotControllerResponseAdvice都不进行包装
        boolean filter =  !returnType.getParameterType().isAssignableFrom(RespVO.class);
        return filter;
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // String类型不能直接包装
        if (returnType.getGenericParameterType().equals(String.class)) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                // 将数据包装在RespVO里后转换为json串进行返回
                return objectMapper.writeValueAsString(new RespVO(body));
            } catch (JsonProcessingException e) {
                throw new BusinessException(BusinessCode.RESPONSE_PACK_ERROR.getCode(), e.getMessage());
            }
        }
        // 否则直接包装成ResultVo返回
        return new RespVO(body);
    }

    @ExceptionHandler({RuntimeException.class})
    public RespVO RuntimeExceptionHandler(RuntimeException e) {
        return new RespVO(BusinessCode.API_ERROR, e.getMessage());
    }

    @ExceptionHandler({BindException.class})
    public RespVO MethodArgumentNotValidExceptionHandler(Exception e) {
        return new RespVO(BusinessCode.VALIDATE_ERROR, e.getMessage());
    }

    @ExceptionHandler({BusinessException.class})
    public RespVO BusinessExceptionHandler(BusinessException e) {
        // TODO: log.error(e.getMessage(), e); 由于还没集成日志框架，暂且放着，写上

//        // 额外的错误信息，被放在了detailMessage里
//        if (e.getCode().equals(BusinessCode.THREE_PARTY_ERROR.getCode())) {
//            return new RespVO(e.getCode(), e.getMessage());
//        }
//
//        if (e.getCode().equals(BusinessCode.TENCENT_SMS_ERROR.getCode())) {
//            return new RespVO(e.getCode(), e.getMessage());
//        }
        return new RespVO(e);
    }

}
